﻿Imports System
Imports System.Collections.Generic
Imports System.Drawing
Imports System.Runtime.CompilerServices
Imports System.Windows.Forms
Imports System.Workflow.ComponentModel

Namespace System.Workflow.ComponentModel.Design
    Friend MustInherit Class ItemStrip
        ' Events
        Public Custom Event ScrollPositionChanged As EventHandler
        Public Custom Event SelectionChanged As SelectionChangeEventHandler([Of] SelectionChangeEventArgs)

        ' Methods
        Public Sub New(ByVal serviceProvider As IServiceProvider, ByVal orientation As Orientation, ByVal itemSize As Size, ByVal margin As Size)
            If (serviceProvider Is Nothing) Then
                Throw New ArgumentNullException("serviceProvider")
            End If
            Me.serviceProvider = serviceProvider
            Me.orientation = orientation
            Me.itemSize = itemSize
            Me.margin = margin
            Me.items = New ItemList([Of] ItemInfo)(Me)
            AddHandler Me.items.ListChanging, New ItemListChangeEventHandler([Of] ItemInfo)(AddressOf Me.OnItemsChanging)
            AddHandler Me.items.ListChanged, New ItemListChangeEventHandler([Of] ItemInfo)(AddressOf Me.OnItemsChanged)
        End Sub

        Public MustOverride Sub Draw(ByVal graphics As Graphics)

        Private Sub EnsureScrollPositionAndSelection()
            Dim scrollPosition As Integer = Me.scrollPosition
            If (Not Me.selectedItem Is Nothing) Then
                Dim index As Integer = Me.items.IndexOf(Me.selectedItem)
                If (index >= 0) Then
                    If (index <= Me.scrollPosition) Then
                        scrollPosition = Math.Max((index - 1), 0)
                    End If
                    Dim maxVisibleItems As Integer = Me.MaxVisibleItems
                    If (index >= ((Me.scrollPosition + maxVisibleItems) - 1)) Then
                        scrollPosition = ((index - maxVisibleItems) + 2)
                    End If
                End If
            End If
            Me.ScrollPosition = scrollPosition
        End Sub

        Public Function GetItemBounds(ByVal itemInfo As ItemInfo) As Rectangle
            Dim index As Integer = Me.items.IndexOf(itemInfo)
            If (((index < 0) OrElse (index < Me.scrollPosition)) OrElse (index >= (Me.scrollPosition + Me.MaxVisibleItems))) Then
                Return Rectangle.Empty
            End If
            Dim empty As Rectangle = Rectangle.Empty
            index = (index - Me.scrollPosition)
            If (Me.orientation = Orientation.Horizontal) Then
                empty.X = ((Me.bounds.Left + (index * Me.itemSize.Width)) + ((index + 1) * Me.margin.Width))
                empty.Y = (Me.bounds.Top + Me.margin.Height)
            Else
                empty.X = (Me.bounds.Left + Me.margin.Width)
                empty.Y = ((Me.bounds.Top + (index * Me.itemSize.Height)) + ((index + 1) * Me.margin.Height))
            End If
            empty.Size = Me.itemSize
            Return empty
        End Function

        Public Function HitTest(ByVal point As Point) As ItemInfo
            Dim info2 As ItemInfo
            For Each info2 In Me.items
                If Me.GetItemBounds(info2).Contains(point) Then
                    Return info2
                End If
            Next
            Return Nothing
        End Function

        Protected Sub Invalidate()
            Dim service As WorkflowView = [TryCast](Me.serviceProvider.GetService(GetType(WorkflowView)),WorkflowView)
            If (Not service Is Nothing) Then
                service.InvalidateLogicalRectangle(Me.bounds)
            End If
        End Sub

        Private Sub OnItemsChanged(ByVal sender As Object, ByVal e As ItemListChangeEventArgs([Of] ItemInfo))
            If (e.Action = ItemListChangeAction.Add) Then
                If (e.AddedItems.Count > 0) Then
                    Me.SelectedItem = e.AddedItems.Item(0)
                End If
            ElseIf (e.Action = ItemListChangeAction.Remove) Then
                Me.EnsureScrollPositionAndSelection
            End If
            Me.Invalidate
        End Sub

        Private Sub OnItemsChanging(ByVal sender As Object, ByVal e As ItemListChangeEventArgs([Of] ItemInfo))
            If (((e.Action = ItemListChangeAction.Remove) AndAlso (e.RemovedItems.Count > 0)) AndAlso (Me.selectedItem Is e.RemovedItems.Item(0))) Then
                Dim index As Integer = Me.items.IndexOf(e.RemovedItems.Item(0))
                index = (index + If((index < (Me.items.Count - 1)), 1, -1))
                Me.SelectedItem = If(((index >= 0) AndAlso (index < Me.items.Count)), Me.items.Item(index), Nothing)
            End If
        End Sub

        Public Overridable Sub OnMouseDown(ByVal e As MouseEventArgs)
            Dim info As ItemInfo = Me.HitTest(New Point(e.X, e.Y))
            If (Not info Is Nothing) Then
                Me.SelectedItem = info
                If ((Not info.Text Is Nothing) AndAlso (info.Text.Length > 0)) Then
                    Me.ShowInfoTip(info.Text)
                End If
            End If
            Me.HighlitedItem = info
        End Sub

        Public Overridable Sub OnMouseDragBegin(ByVal initialDragPoint As Point, ByVal e As MouseEventArgs)
        End Sub

        Public Overridable Sub OnMouseDragEnd()
        End Sub

        Public Overridable Sub OnMouseDragMove(ByVal e As MouseEventArgs)
        End Sub

        Public Overridable Sub OnMouseEnter(ByVal e As MouseEventArgs)
            Dim info As ItemInfo = Me.HitTest(New Point(e.X, e.Y))
            If (((Not info Is Nothing) AndAlso (Not info.Text Is Nothing)) AndAlso (info.Text.Length > 0)) Then
                Me.ShowInfoTip(info.Text)
            End If
            Me.HighlitedItem = info
        End Sub

        Public Overridable Sub OnMouseLeave()
            Me.ShowInfoTip(String.Empty)
            Me.HighlitedItem = Nothing
        End Sub

        Public Overridable Sub OnMouseMove(ByVal e As MouseEventArgs)
            Dim info As ItemInfo = Me.HitTest(New Point(e.X, e.Y))
            If (((Not info Is Nothing) AndAlso (Not info.Text Is Nothing)) AndAlso (info.Text.Length > 0)) Then
                Me.ShowInfoTip(info.Text)
            End If
            Me.HighlitedItem = info
        End Sub

        Public Overridable Sub OnMouseUp(ByVal e As MouseEventArgs)
        End Sub

        Private Sub ShowInfoTip(ByVal infoTip As String)
            Dim service As WorkflowView = [TryCast](Me.serviceProvider.GetService(GetType(WorkflowView)),WorkflowView)
            If (Not service Is Nothing) Then
                service.ShowInfoTip(String.Empty, infoTip)
            End If
        End Sub


        ' Properties
        Public ReadOnly Property Bounds As Rectangle
            Get
                Return Me.bounds
            End Get
        End Property

        Property HighlitedItem As ItemInfo
            Protected Get
                Return Me.highlitedItem
            End Get
            Private Set(ByVal value As ItemInfo)
                If (Not Me.highlitedItem Is value) Then
                    Me.highlitedItem = value
                    Me.Invalidate
                End If
            End Set
        End Property

        Public ReadOnly Property Items As IList([Of] ItemInfo)
            Get
                Return Me.items
            End Get
        End Property

        Public ReadOnly Property ItemSize As Size
            Get
                Return Me.itemSize
            End Get
        End Property

        Public Property Location As Point
            Get
                Return Me.bounds.Location
            End Get
            Set(ByVal value As Point)
                If (Me.bounds.Location <> value) Then
                    Me.Invalidate
                    Me.bounds.Location = value
                    Me.Invalidate
                End If
            End Set
        End Property

        Protected Friend ReadOnly Property MaxVisibleItems As Integer
            Get
                Dim num As Integer = 0
                If (Me.orientation = Orientation.Horizontal) Then
                    Dim num2 As Integer = (Me.bounds.Width - Me.margin.Width)
                    num = (num2 / Math.Max((Me.itemSize.Width + Me.margin.Width), 1))
                Else
                    Dim num3 As Integer = (Me.bounds.Height - Me.margin.Height)
                    num = (num3 / Math.Max((Me.itemSize.Height + Me.margin.Height), 1))
                End If
                Return Math.Max(num, 1)
            End Get
        End Property

        Public ReadOnly Property RequiredSize As Size
            Get
                Dim empty As Size = Size.Empty
                If (Me.orientation = Orientation.Horizontal) Then
                    empty.Width = ((Me.items.Count * Me.itemSize.Width) + ((Me.items.Count + 1) * Me.margin.Width))
                    empty.Height = (Me.itemSize.Height + (2 * Me.margin.Height))
                    Return empty
                End If
                empty.Width = (Me.itemSize.Width + (2 * Me.margin.Width))
                empty.Height = ((Me.items.Count * Me.itemSize.Height) + ((Me.items.Count + 1) * Me.margin.Height))
                Return empty
            End Get
        End Property

        Public Property ScrollPosition As Integer
            Get
                Return Me.scrollPosition
            End Get
            Set(ByVal value As Integer)
                If (value >= 0) Then
                    Dim num As Integer = value
                    Dim maxVisibleItems As Integer = Me.MaxVisibleItems
                    If ((Me.items.Count >= maxVisibleItems) AndAlso ((Me.items.Count - num) < maxVisibleItems)) Then
                        num = (Me.items.Count - maxVisibleItems)
                    End If
                    If ((num >= 0) AndAlso (num <= Math.Max(((Me.items.Count - maxVisibleItems) + 1), 0))) Then
                        Me.scrollPosition = num
                        Me.Invalidate
                        If (Not Me.ScrollPositionChanged Is Nothing) Then
                            Me.ScrollPositionChanged.Invoke(Me, EventArgs.Empty)
                        End If
                    End If
                End If
            End Set
        End Property

        Public Property SelectedItem As ItemInfo
            Get
                Return Me.selectedItem
            End Get
            Set(ByVal value As ItemInfo)
                If (Not Me.selectedItem Is value) Then
                    Dim selectedItem As ItemInfo = Me.selectedItem
                    Me.selectedItem = value
                    Me.EnsureScrollPositionAndSelection
                    Me.Invalidate
                    If (Not Me.SelectionChanged Is Nothing) Then
                        Me.SelectionChanged.Invoke(Me, New SelectionChangeEventArgs(selectedItem, Me.selectedItem))
                    End If
                End If
            End Set
        End Property

        Public Property Size As Size
            Get
                Return Me.bounds.Size
            End Get
            Set(ByVal value As Size)
                If (Me.bounds.Size <> value) Then
                    Me.Invalidate
                    Me.bounds.Size = value
                    Me.EnsureScrollPositionAndSelection
                    Me.Invalidate
                End If
            End Set
        End Property


        ' Fields
        Private bounds As Rectangle = Rectangle.Empty
        Private highlitedItem As ItemInfo
        Private items As ItemList([Of] ItemInfo)
        Private itemSize As Size = New Size(&H10, &H10)
        Private margin As Size = Size.Empty
        Private orientation As Orientation
        Private scrollPosition As Integer
        Private selectedItem As ItemInfo
        Protected serviceProvider As IServiceProvider
    End Class
End Namespace

